/*
 * CategorizedXMLEntity.java
 *
 * Created on July 17, 2007, 2:46 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.client;

import java.net.URI;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.Item;
import org.infoset.xml.Named;
import org.restlet.data.MediaType;

/**
 *
 * @author alex
 */
public class CategorizedXMLEntity extends XMLEntity implements AtomEntity
{
   
   static DateFormat getDateAndTimeFormatter() {
      return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
   }
   
   public static String toXSDDate(Date d) {
      DateFormat format = getDateAndTimeFormatter();
      String v = format.format(d);
      return v.substring(0,22)+':'+v.substring(22);
   }
   
   public static Date fromXSDDate(String value) 
      throws java.text.ParseException
   {
      DateFormat format = getDateAndTimeFormatter();
      String wocolon = value.substring(0,22)+value.substring(23);
      return format.parse(wocolon);
   }
   
   Map<URI,Term> terms;
   LinkSet linkset;
   
   /** Creates a new instance of CategorizedXMLEntity */
   public CategorizedXMLEntity(Document doc)
   {
      super(doc);
      terms = null;
   }
   
   public void index() {
      terms = new TreeMap<URI,Term>();
      Iterator<Element> categories = doc.getDocumentElement().getElementsByName(XML.CATEGORY_NAME);
      while (categories.hasNext()) {
         Element categoryE = categories.next();
         Term term = Term.derive(categoryE);
         if (term!=null) {
            Term prevTerm = terms.get(term.getURI());
            if (prevTerm==null) {
               terms.put(term.getURI(),term);
            } else {
               prevTerm.add(term.getFirstValue());
            }
         }
      }
      linkset = new LinkSet();
      Iterator<Element> links = doc.getDocumentElement().getElementsByName(XML.LINK_NAME);
      while (links.hasNext()) {
         Element linkE = links.next();
         String rel = linkE.getAttributeValue("rel");
         String type = linkE.getAttributeValue("type");
         String href = linkE.getAttributeValue("href");
         if (rel!=null && href!=null) {
            URI base = linkE.getBaseURI();
            URI location = base!=null ? base.resolve(href) : URI.create(href);
            MediaType mtype = type==null ? null : MediaType.valueOf(type);
            Link link = new Link(rel,mtype,location);
            List<Link> list = (List<Link>)linkset.get(rel);
            if (list==null) {
               list = new ArrayList<Link>();
               linkset.put(rel,list);
            }
            list.add(link);
         }
      }
   }
   
   public String getId() {
      Element idE = doc.getDocumentElement().getFirstElementNamed(XML.ID_NAME);
      return idE==null ? null : idE.getText();
   }
   
   public void setId(String uri)
   {
      Element idE = doc.getDocumentElement().getFirstElementNamed(XML.ID_NAME);
      if (idE==null) {
         if (doc.getDocumentElement().size()==0) {
            idE = doc.getDocumentElement().addElement(XML.ID_NAME);
         } else {
            idE = doc.getDocumentElement().addElement(0,XML.ID_NAME);
         }
      }
      idE.clear();
      idE.addCharacters(uri);
   }
   
   public String getTitle() {
      Element titleE = doc.getDocumentElement().getFirstElementNamed(XML.TITLE_NAME);
      return titleE==null ? null : titleE.getText();
   }
   
   public Text getTitleText(boolean create)
   {
      Element titleE = doc.getDocumentElement().getFirstElementNamed(XML.TITLE_NAME);
      if (titleE==null && create) {
         titleE = doc.getDocumentElement().addElement(XML.TITLE_NAME);
      }
      return titleE==null ? null : new Text(titleE);
   }
   
   public void setTitle(String text)
   {
      Element titleE = doc.getDocumentElement().getFirstElementNamed(XML.TITLE_NAME);
      if (titleE==null) {
         if (doc.getDocumentElement().size()==0) {
            titleE = doc.getDocumentElement().addElement(XML.TITLE_NAME);
         } else {
            titleE = doc.getDocumentElement().addElement(0,XML.TITLE_NAME);
         }
      }
      titleE.clear();
      titleE.addCharacters(text);
   }
   
   public String getSummary() {
      Element summaryE = doc.getDocumentElement().getFirstElementNamed(XML.SUMMARY_NAME);
      return summaryE==null ? null : summaryE.getText();
   }
   
   public Text getSummaryText(boolean create)
   {
      Element summaryE = doc.getDocumentElement().getFirstElementNamed(XML.SUMMARY_NAME);
      if (summaryE==null && create) {
         summaryE = doc.getDocumentElement().addElement(XML.SUMMARY_NAME);
      }
      return summaryE==null ? null : new Text(summaryE);
   }
   
   public void setSummary(String text)
   {
      Element summaryE = doc.getDocumentElement().getFirstElementNamed(XML.SUMMARY_NAME);
      if (summaryE==null) {
         if (doc.getDocumentElement().size()==0) {
            summaryE = doc.getDocumentElement().addElement(XML.SUMMARY_NAME);
         } else {
            summaryE = doc.getDocumentElement().addElement(0,XML.SUMMARY_NAME);
         }
      }
      summaryE.clear();
      summaryE.addCharacters(text);
   }

   public Map<URI,Term> getTerms() {
      return terms==null ? null : Collections.unmodifiableMap(terms);
   }
   
   public Term getTerm(URI term) {
      return terms.get(term);
   }
   
   public void removeTerm(URI term) {
      terms.remove(term);
   }
   
   public void addTerm(Term term) {
      terms.put(term.getURI(),term);
   }
   
   public LinkSet getLinks() {
      return linkset;
   }
   
   public Date getUpdated() 
      throws ParseException
   {
      Element dateE = doc.getDocumentElement().getFirstElementNamed(XML.UPDATED_NAME);
      return dateE==null ? null : fromXSDDate(dateE.getText());
   }
   
   public void setUpdated(Date date)
   {
      Element dateE = doc.getDocumentElement().getFirstElementNamed(XML.UPDATED_NAME);
      if (dateE==null) {
         dateE = doc.getDocumentElement().addElement(XML.UPDATED_NAME);
      }
      dateE.clear();
      dateE.addCharacters(toXSDDate(date));
   }
   
   public Date getPublished() 
      throws ParseException
   {
      Element dateE = doc.getDocumentElement().getFirstElementNamed(XML.PUBLISHED_NAME);
      return dateE==null ? null : fromXSDDate(dateE.getText());
   }
   public void setPublished(Date date)
   {
      Element dateE = doc.getDocumentElement().getFirstElementNamed(XML.PUBLISHED_NAME);
      if (dateE==null) {
         dateE = doc.getDocumentElement().addElement(XML.PUBLISHED_NAME);
      }
      dateE.clear();
      dateE.addCharacters(toXSDDate(date));
   }
   
   public Date getEdited() 
      throws ParseException
   {
      Element dateE = doc.getDocumentElement().getFirstElementNamed(XML.EDITED_NAME);
      return dateE==null ? null : fromXSDDate(dateE.getText());
   }
   public void setEdited(Date date)
   {
      Element dateE = doc.getDocumentElement().getFirstElementNamed(XML.EDITED_NAME);
      if (dateE==null) {
         dateE = doc.getDocumentElement().addElement(XML.EDITED_NAME);
      }
      dateE.clear();
      dateE.addCharacters(toXSDDate(date));
   }
   
   public void update() {
      Element entryE = doc.getDocumentElement();
      Iterator<Element> categories = entryE.getElementsByName(XML.CATEGORY_NAME);
      while (categories.hasNext()) {
         Element categoryE = categories.next();
         categories.remove();
      }
      Iterator<Element> links = entryE.getElementsByName(XML.LINK_NAME);
      while (links.hasNext()) {
         Element linkE = links.next();
         links.remove();
      }
      int idPos = 0;
      for (int i=0; i<entryE.size(); i++) {
         if (entryE.get(i).getType()==Item.ItemType.ElementItem && ((Named)entryE).getName().equals(XML.ID_NAME)) {
            idPos = i;
            break;
         }
      }
      idPos++;
      if (idPos==entryE.size()) {
         idPos = -1;
      }
      for (URI termId : terms.keySet()) {
         Term term = terms.get(termId);
         URI uscheme = term.getScheme();
         String scheme = uscheme.equals(term.DEFAULT_SCHEME) ? null : uscheme.toString();
         String name = term.getName();
         if (name.length()==0) {
            name = "#";
         }
         if (term.getValues()!=null) {
            for (String value : term.getValues()) {
               Element categoryE = idPos<0 ? entryE.addElement(XML.CATEGORY_NAME) : entryE.addElement(idPos,XML.CATEGORY_NAME);
               if (scheme!=null) {
                  categoryE.setAttributeValue("scheme",scheme);
               }
               categoryE.setAttributeValue("term",name);
               categoryE.addCharacters(value);
            }
         } else {
            Element categoryE = idPos<0 ? entryE.addElement(XML.CATEGORY_NAME) : entryE.addElement(idPos,XML.CATEGORY_NAME);
            if (scheme!=null) {
               categoryE.setAttributeValue("scheme",scheme);
            }
            categoryE.setAttributeValue("term",name);
         }
      }
      URI base = entryE.getBaseURI();
      for (String rel : linkset.keySet()) {
         List<Link> relLinks = linkset.get(rel);
         for (Link link : relLinks) {
            Element linkE = idPos<0 ? entryE.addElement(XML.LINK_NAME) : entryE.addElement(idPos,XML.LINK_NAME);
            linkE.setAttributeValue("href",base==null ? link.getLink().toString() : base.relativize(link.getLink()).toString());
            if (link.getType()!=null) {
               linkE.setAttributeValue("type",link.getType().toString());
            }
            linkE.setAttributeValue("rel",link.getRelation());
         }
      }
   }
}
